package asteroids.model;

import be.kuleuven.cs.som.annotate.Basic;

/**
 * @version 0.3
 * @author  Tandan Sunil, Van Deun Luca
 */
public class Vector {

	/**
	 * Creates a new vector with the given x- and y-components.
	 * @param xComponent
	 * 		  The x-component of this new vector.
	 * @param yComponent
	 * 		  The y-component of this new vector.
	 * @throws IllegalArgumentException
	 *			| !isValidComponent(xCoordinate) || !isValidComponent(yCoordinate)
	 */
	public Vector(double xComponent, double yComponent) throws IllegalArgumentException{
		setXComponent(xComponent);
		setYComponent(yComponent);
	}
	
	public Vector(){
		
	}
	
	private double xComponent;
	private double yComponent;
	
	/**
	 *Returns the x-component of this vector. 
	 *
	 */
	@Basic
	public double getXComponent(){
		return xComponent;
	}
	
	/**
	 *Returns the y-component of this vector. 
	 *
	 */
	@Basic
	public double getYComponent(){
		return yComponent;
	}
	
	/**
	 * Sets the xComponent of this vector.
	 *  
	 * @param xComponent
	 * 		  The x-component that has to be set.
	 * 
	 * @post ...
	 * 		 | new.getXComponent() == xComponent
	 * 
	 * @throws IllegalArgumentException
	 * 		 | (!isValidComponent)
	 */
	public void setXComponent(double xComponent) throws IllegalArgumentException{
		if(!isValidComponent(xComponent))
			throw new IllegalArgumentException("Invalid xComponent:"+ xComponent);
		this.xComponent = xComponent;
	}
	
	/**
	 * Sets the yComponent of this vector.
	 *  
	 * @param yComponent
	 * 		  The y-component that has to be set.
	 * 
	 * @post ...
	 * 		 | new.getYComponent() == yComponent
	 * 
	 * @throws IllegalArgumentException
	 * 		 | (!isValidComponent)
	 */
	public void setYComponent(double yComponent) throws IllegalArgumentException{
		if(!isValidComponent(yComponent))
			throw new IllegalArgumentException("Invalid yComponent");
		this.yComponent = yComponent;
	}
	
	/**
	 * Checks if the given component is valid. 
	 * @param 	component
	 * 			The component to be checked.
	 * @return
	 * 			| result != (Double.isNaN(component) || component == Double.POSITIVE_INFINITY || component == Double.NEGATIVE_INFINITY) 
	 */
	public static boolean isValidComponent(double component){
		if(Double.isNaN(component) || component == Double.POSITIVE_INFINITY || component == Double.NEGATIVE_INFINITY)
			return false;	
		return true;
	}
		
	/**
	 * Returns the length of this vector using pythagoras theorem.
	 * @return	...
	 * 			| result == (Math.sqrt(Math.pow(getXComponent(),2)+Math.pow(getYComponent(),2)))
	 * 
	 */
	public double getLength(){
		return (Math.sqrt(Math.pow(getXComponent(),2)+Math.pow(getYComponent(),2)));
	}
	
	/**
	 * 
	 * Give the dot product of two given arrays of length equal to 2.
	 * 
	 * @param 	 	  vector1
	 * 				  The first vector.
	 * @param 		  vector2
	 * 				  The second vector.
	 * @pre			 ...
	 * 				| !(isValidComponent(vector1.getXComponent())) && !(isValidComponent(vector1.getYComponent())) &&
	 * 				| !(isValidComponent(vector2.getXComponent())) && !(isValidComponent(vector2.getYComponent()))
	 * 
	 * @return		  Returns the dot product of given arrays.
	 * 				| result == vector1.getXComponent()*vector2.getXComponent()
	 * 							+vector1.getYComponent()*vector2.getYComponent()
	 */		
	public static double dotProduct(Vector vector1, Vector vector2){
		assert(vector1 != null && vector2 != null ||((isValidComponent(vector1.getXComponent())) 
				&& !(isValidComponent(vector1.getYComponent())) && !(isValidComponent(vector2.getXComponent()))
				&& !(isValidComponent(vector2.getYComponent())) ));
		return (vector1.getXComponent()*vector2.getXComponent()+vector1.getYComponent()*vector2.getYComponent());
	}

	/**
	 * Transforms the given x- and y-velocity to new x- and y-velocity with the same total direction and of which the total value is equal to the given max.
	 * 
	 * @param 	 vector
	 * 			 The vector to be transformed.
	 * @param 	 maxLength
	 * 			 The maximum value of the vector.
	 * 
	 * @pre		 The given vector is valid.
	 * 		    | isValidVector(vector)
	 * 		 
	 * @return 	 Returns the new velocities with the same direction as the original velocities and of which the total value is equal to the given max.
	 * 			|result.getLength() == maxLength
	 * 			|result.getXComponent()/result.getYComponent() == vector.getXComponent()/vector.getYComponent()
	 */
	public static Vector transformVector(Vector vector, double maxLength){
		assert(isReadyToTransform(vector));
		double ratio = Math.abs(vector.getXComponent()/vector.getYComponent());
		double newYVelocity = Math.sqrt(Math.pow(maxLength,2)/((ratio*ratio) + 1));
		double newXVelocity = ratio * newYVelocity;
		Vector tempVector= new Vector();;
		if(vector.getXComponent() < 0)
			tempVector.setXComponent(-1 * newXVelocity);
		else
			tempVector.setXComponent(newXVelocity);
		if(vector.getYComponent() < 0)
			tempVector.setYComponent(-1 * newYVelocity);
		
		else
			tempVector.setYComponent(newYVelocity);
		return tempVector;
	}

	/**
	 * Checks whether the given velocity is valid.
	 * 
	 * @param 	  	  vector
	 * 				  The vector to be checked.
	 * 				
	 * @return		  Returns true if the components of the given vector are not infinity and not NaN.
	 * 				| result != 
	 * 						(Double.isNaN(vector.getXComponent()) || vector.getXComponent()==Double.POSITIVE_INFINITY  || vector.getXComponent() == Double.NEGATIVE_INFINITY || vector.getXComponent() == 0) &&
	 * 						(Double.isNaN(vector.getYComponent()) || vector.getYComponent()==Double.POSITIVE_INFINITY  || vector.getYComponent() == Double.NEGATIVE_INFINITY || vector.getYComponent() == 0)
	 */
	public static boolean isReadyToTransform(Vector vector){
		
		if(Double.isNaN(vector.getXComponent()) || vector.getXComponent()==Double.POSITIVE_INFINITY  || vector.getXComponent() == Double.NEGATIVE_INFINITY || vector.getXComponent() == 0)
			return false;
		if(Double.isNaN(vector.getYComponent()) || vector.getYComponent()==Double.POSITIVE_INFINITY  || vector.getYComponent() == Double.NEGATIVE_INFINITY || vector.getYComponent() == 0)
			return false;
		
		return true;
	}
	
	/**
	 * Returns the distance between this vector and the other vector. 
	 * @param other
	 * 		| The other vector with which the distance has to be calculated.
	 * @return
	 * 		| result == (Math.sqrt(Math.pow((this.getXComponent()-other.getXComponent()),2)+Math.pow((this.getYComponent()-other.getYComponent()), 2)))
	 */
	public double distanceTo(Vector other){
		return (Math.sqrt(Math.pow((this.getXComponent()-other.getXComponent()),2)+Math.pow((this.getYComponent()-other.getYComponent()), 2)));
	}

}
